﻿using System;
using System.Collections.Generic;
using System.Linq;
using ITM.Modules.SharePointFileExplorer.WSLists;
using ITM.Modules.SharePointFileExplorer.WSDws;
using ITM.Modules.SharePointFileExplorer.WSCopy;
using System.Net;
using System.Xml;
using System.IO;

namespace ITM.Modules.SharePointFileExplorer.SharePoint
{
    public class SharePointController
    {
        // Variables
        private string _sharepointUsername;
        private string _sharepointPassword;
        private string _sharepointDomain;
        private string _sharepointUrl;
        private Lists _listsService;
        private Copy _copyService;
        private Dws _dwsService;
        private NetworkCredential _sharepointNetworkCredential;
        // Constants
        private const string LISTS = @"_vti_bin/Lists.asmx";
        private const string COPY = @"_vti_bin/Copy.asmx";
        private const string DWS = @"_vti_bin/Dws.asmx";
        // Properties
        public NetworkCredential SharepointNetworkCredential
        { 
            get 
            {
                if (_sharepointNetworkCredential == null)
                {
                    _sharepointNetworkCredential = new NetworkCredential(_sharepointUsername, _sharepointPassword, _sharepointDomain);
                }
                return _sharepointNetworkCredential;
            }

            set
            {
                _sharepointNetworkCredential = value;
            }
        }
        public Lists ListsService 
        {
            get {
                if (_listsService == null)
                {
                    if (!this._sharepointUrl.EndsWith("/"))
                        this._sharepointUrl += "/";
                    _listsService = new Lists()
                    {
                        Url = this._sharepointUrl + LISTS,
                        Credentials = SharepointNetworkCredential
                    };
                }
                return _listsService;
            }
        }
        public Copy CopyService 
        {
            get
            {
                if (_copyService == null)
                {
                    if (!this._sharepointUrl.EndsWith("/"))
                        this._sharepointUrl += "/";
                    _copyService = new Copy() 
                    { 
                        Url = this._sharepointUrl + COPY,
                        Credentials = SharepointNetworkCredential
                    };
                }
                return _copyService;
            } 
        }
        public Dws DwsService
        {
            get
            {
                if (_dwsService == null)
                {
                    if (!this._sharepointUrl.EndsWith("/"))
                        this._sharepointUrl += "/";
                    _dwsService = new Dws()
                    {
                        Url = this._sharepointUrl + DWS,
                        Credentials = SharepointNetworkCredential
                    };
                }
                return _dwsService;
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="domain"></param>
        /// <param name="url"></param>
        public SharePointController(string username, string password, string domain, string url) 
        {
            this._sharepointUsername = username;
            this._sharepointPassword = password;
            this._sharepointDomain = domain;
            this._sharepointUrl = url;
        }

        public SharePointController(NetworkCredential networkCredential, string url)
        {
            SharepointNetworkCredential = networkCredential;
            this._sharepointUrl = url;
        }

        /// <summary>
        /// Get document libraries under a specific url
        /// </summary>
        /// <returns></returns>
        public List<string> SPGetDocumentLibraries()
        {
            List<string> documentLibraries = new List<string>();
            try
            {
                XmlNode ndLists = ListsService.GetListCollection();
                foreach (XmlElement elem in ndLists.ChildNodes)
                {
                    if (elem.GetAttribute("ServerTemplate").Equals("101"))
                    {
                        // Document library name 
                        string documentLibraryName = elem.GetAttribute("Title");
                        documentLibraries.Add(documentLibraryName);
                    }
                }
                return documentLibraries;
            }
            catch
            {
                throw new Exception("SPGetDocumentLibraries failed, please check your information for SharePoint again");
            }

        }

        public List<DocumentLibraryInfo> SPGetDocumentLibraryInfos()
        {
            List<DocumentLibraryInfo> documentLibraryInfoList = new List<DocumentLibraryInfo>();
            try
            {
                XmlNode ndLists = ListsService.GetListCollection();
                foreach (XmlElement elem in ndLists.ChildNodes)
                {
                    // "101" means it is document library
                    if (elem.GetAttribute("ServerTemplate").Equals("101"))
                    {
                        DocumentLibraryInfo documentLibraryInfo = new DocumentLibraryInfo();
                        // name 
                        documentLibraryInfo.DocumentLibraryName = elem.GetAttribute("Title");
                        // description
                        documentLibraryInfo.DocumentLibraryDescription = elem.OuterXml.Contains("Description") ? elem.GetAttribute("Description") : "";
                        // item count
                        documentLibraryInfo.DocumentLibraryItemCount = elem.OuterXml.Contains("ItemCount") ? int.Parse(elem.GetAttribute("ItemCount")) : 0;
                        documentLibraryInfoList.Add(documentLibraryInfo);
                    }
                }
                return documentLibraryInfoList;
            }
            catch
            {
                throw new Exception("SPGetDocumentLibraryInfo failed");
            }

        }

        /// <summary>
        /// Get document librarie properties: name and viewName 
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> SPGetDocumentLibraryProperties()
        {
            // <documentlibraryName, documentLibraryViewName>
            Dictionary<string, string> documentLibraries = new Dictionary<string, string>();
            try
            {
                XmlNode ndLists = ListsService.GetListCollection();
                foreach (XmlElement elem in ndLists.ChildNodes)
                {
                    if (elem.GetAttribute("ServerTemplate").Equals("101"))
                    {
                        // Document library name
                        string documentLibraryName = elem.GetAttribute("Title");
                        // ex. /communities/SiteAssets/Forms/AllItems.aspx 
                        string defaultViewUrl = elem.GetAttribute("DefaultViewUrl");
                        // ex. /communities 
                        string webFullUrl = elem.GetAttribute("WebFullUrl");
                        if (defaultViewUrl.Length > 0 && webFullUrl.Length > 0)
                        {
                            webFullUrl += "/";
                            string documentLibraryViewName = null;
                            if (defaultViewUrl.Contains(webFullUrl))
                                documentLibraryViewName = defaultViewUrl.TrimStart(webFullUrl.ToCharArray());
                            else
                                documentLibraryViewName = defaultViewUrl;
                            // Document library view Name
                            documentLibraryViewName = documentLibraryViewName.Substring(0, documentLibraryViewName.IndexOf('/'));
                            documentLibraries.Add(documentLibraryName, documentLibraryViewName);
                        }
                    }
                }
                return documentLibraries;
            }
            catch
            {
                throw new Exception("SPGetDocumentLibraryProperties failed");
            }
        }

        /// <summary>
        /// Get files or folder under specific folder inside a specific document library
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="folderPath"></param>
        /// <param name="itemType"></param>
        /// <returns></returns>
        private XmlNode SPGetItems(string documentLibraryName, string folderPath, string itemType)
        {
            XmlNode ndListItems = null;
            XmlDocument xmlDoc = new XmlDocument();
            XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            // Pay attention to folderPath
            ndQueryOptions.InnerXml = @"<QueryOptions>
                                          <ViewAttributes Scope='RecursiveAll'/>
                                          <Folder>" +
                                            folderPath +
                                          "</Folder>" +
                                       "</QueryOptions>";
            ndViewFields.InnerXml = "";
            ndQuery.InnerXml = @"<Where>
                                   <Eq>
                                     <FieldRef Name='FSObjType'/>
                                       <Value Type='Lookup'>" +
                                         itemType +
                                      "</Value>" +
                                    "</Eq>" +
                                "</Where>";
            try
            {
                ndListItems = ListsService.GetListItems(documentLibraryName, null, ndQuery, ndViewFields, null,
                    ndQueryOptions, null);
                return ndListItems;
            }
            catch
            {
                throw new Exception("GetItems failed");
            }
        }

        /// <summary>
        /// Get all folders under a specific path
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="folderPath">relative path (documentlibraryview/folder/subfolder)</param>
        /// <returns></returns>
        public List<string> SPGetFolders(string documentLibraryName, string documentLibraryViewName, string folderPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            List<string> folderList = new List<string>();
            if (!folderPath.EndsWith("/"))
                folderPath += "/";
            XmlNode ndListItems = SPGetItems(documentLibraryName, folderPath, "1");
            if (ndListItems == null)
                return null;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList folders = xmlDoc.GetElementsByTagName("z:row");
                for (int i = 0; i < folders.Count; i++)
                {
                    string folderName = folders.Item(i).OuterXml.Contains("ows_LinkFilename") ? folders.Item(i).Attributes["ows_LinkFilename"].Value : "";
                    string folderServerUrl = folders.Item(i).OuterXml.Contains("ows_ServerUrl") ? folders.Item(i).Attributes["ows_ServerUrl"].Value : "";
                    if (folderPath == "")
                        folderPath = documentLibraryViewName + "/";
                    if (folderName != null && folderServerUrl != null)
                    {
                        if (folderServerUrl.Contains(folderPath + folderName))
                        {
                            folderList.Add(folderName);
                        }
                    }
                }
                return folderList;
            }
        }

        /// <summary>
        /// Get information of all folders within a specific path
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="folderPath">relative path (documentlibraryVIEWname/folder/subfolder)</param>
        /// <returns></returns>
        public List<FolderInfo> SPGetFolderInfos(string documentLibraryName, string documentLibraryViewName, string folderPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            List<FolderInfo> folderInfoList = new List<FolderInfo>();
            if (!folderPath.EndsWith("/"))
                folderPath += "/";
            XmlNode ndListItems = SPGetItems(documentLibraryName, folderPath, "1");
            if (ndListItems == null)
                return null;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList folders = xmlDoc.GetElementsByTagName("z:row");
                for (int i = 0; i < folders.Count; i++)
                {
                    string folderName = folders.Item(i).OuterXml.Contains("ows_LinkFilename") ? folders.Item(i).Attributes["ows_LinkFilename"].Value : "";
                    string folderServerUrl = folders.Item(i).OuterXml.Contains("ows_ServerUrl") ? folders.Item(i).Attributes["ows_ServerUrl"].Value : "";
                    if (folderPath == "")
                        folderPath = documentLibraryViewName + "/";
                    if (folderName != null && folderServerUrl != null)
                    {
                        if (folderServerUrl.Contains(folderPath + folderName))
                        {
                            // creator of folder
                            string folderAuthor = folders.Item(i).OuterXml.Contains("ows_Author") ? folders.Item(i).Attributes["ows_Author"].Value : "";
                            if(folderAuthor.Contains('#'))
                                folderAuthor = folderAuthor.Substring(folderAuthor.LastIndexOf('#') + 1);
                            // editor of folder
                            string folderModifiedBy = folders.Item(i).OuterXml.Contains("ows_Editor") ? folders.Item(i).Attributes["ows_Editor"].Value : "";
                            if (folderModifiedBy.Contains('#'))
                                folderModifiedBy = folderModifiedBy.Substring(folderModifiedBy.LastIndexOf('#') + 1);
                            FolderInfo folderInfo = new FolderInfo();
                            folderInfo.FolderName = folderName;
                            folderInfo.FolderRelativePath = folderPath + folderName;
                            folderInfo.FolderID = folders.Item(i).OuterXml.Contains("ows_ID") ? folders.Item(i).Attributes["ows_ID"].Value : "";
                            folderInfo.FolderCreatedTime = folders.Item(i).OuterXml.Contains("ows_Created") ? folders.Item(i).Attributes["ows_Created"].Value : "";
                            folderInfo.FolderLastModificationTime = folders.Item(i).OuterXml.Contains("ows_Modified") ? folders.Item(i).Attributes["ows_Modified"].Value : "";
                            folderInfo.FolderAuthor = folderAuthor;
                            folderInfo.FolderModifiedBy = folderModifiedBy;
                            folderInfoList.Add(folderInfo);
                        }
                    }
                }
                return folderInfoList;
            }
        }

        /// <summary>
        /// Get properties of files in a specific folder
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="folderPath"></param>
        /// <returns></returns>
        public List<FileInfo> SPGetFileInfos(string documentLibraryName, string documentLibraryViewName, string folderPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            List<FileInfo> fileInfoList = new List<FileInfo>();
            XmlNode ndListItems = SPGetItems(documentLibraryName, folderPath, "0");
            if (ndListItems == null)
                return null;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList files = xmlDoc.GetElementsByTagName("z:row");
                for (int i = 0; i < files.Count; i++)
                {
                    string fileName = files.Item(i).OuterXml.Contains("ows_LinkFilename") ? files.Item(i).Attributes["ows_LinkFilename"].Value : "";
                    string fileServerUrl = files.Item(i).OuterXml.Contains("ows_ServerUrl") ? files.Item(i).Attributes["ows_ServerUrl"].Value : "";
                    if (folderPath == "")
                        folderPath = documentLibraryViewName + "/";
                    // process to get fake path
                    string[] strArray = folderPath.Split('/');
                    strArray[0] = documentLibraryName;
                    string fakeFolderPath = string.Empty;
                    foreach (var str in strArray)
                    {
                        if ((str != null) && (str != ""))
                        {
                            fakeFolderPath += str + "/";
                        }
                    }
                    if (fileName != null && fileServerUrl != null)
                    {
                        if (fileServerUrl.Contains(folderPath + fileName))
                        {
                            // Initialize FileInfo 
                            FileInfo fileInfo = new FileInfo();
                            string fileModifiedBy = files.Item(i).OuterXml.Contains("ows_Author") ? files.Item(i).Attributes["ows_Author"].Value : "";
                            if(fileModifiedBy.Contains("#"))
                                fileModifiedBy = fileModifiedBy.Substring(fileModifiedBy.LastIndexOf('#') + 1);
                            fileInfo.FileID = files.Item(i).OuterXml.Contains("ows_ID") ? files.Item(i).Attributes["ows_ID"].Value : "";
                            fileInfo.FileBaseName = files.Item(i).OuterXml.Contains("ows_BaseName") ? files.Item(i).Attributes["ows_BaseName"].Value : "";
                            fileInfo.FileName = fileName;
                            fileInfo.FileExtension = files.Item(i).OuterXml.Contains("ows_DocIcon") ? files.Item(i).Attributes["ows_DocIcon"].Value : "";
                            fileInfo.FileLastModificationTime = files.Item(i).OuterXml.Contains("ows_Modified") ? files.Item(i).Attributes["ows_Modified"].Value : "";
                            fileInfo.FileCreatedTime = files.Item(i).OuterXml.Contains("ows_Created") ? files.Item(i).Attributes["ows_Created"].Value : "";
                            fileInfo.FileAuthor = files.Item(i).OuterXml.Contains("ows__Author") ? files.Item(i).Attributes["ows__Author"].Value : "";
                            fileInfo.FileModifiedBy = fileModifiedBy;
                            fileInfo.FileRelativePath = folderPath + fileName; //documentlibraryviewname/folder/subfolder
                            fileInfo.FileFakeRelativePath = fakeFolderPath + fileName; //documentlibrary/folder/subfolder
                            fileInfo.FileSize = int.Parse(files.Item(i).OuterXml.Contains("ows_FileSizeDisplay") ? files.Item(i).Attributes["ows_FileSizeDisplay"].Value : "");      
                            fileInfoList.Add(fileInfo);
                        }
                    }
                }
                return fileInfoList;
            }
        }

        /// <summary>
        /// Get files in a specific folder
        /// folderpath should be given value in form of documentlibraryviewname/folder/subfolder/
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="folderPath"> relative path (documentlibraryviewname/folder/subfolder/)</param>
        /// <returns></returns>
        public List<string> SPGetFiles(string documentLibraryName, string documentLibraryViewName, string folderPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            List<string> fileList = new List<string>();
            if (!folderPath.EndsWith("/"))
                folderPath += "/";
            XmlNode ndListItems = SPGetItems(documentLibraryName, folderPath, "0");
            if (ndListItems == null)
                return null;
            else
            {
                xmlDoc.LoadXml(ndListItems.OuterXml);
                XmlNodeList files = xmlDoc.GetElementsByTagName("z:row");
                for (int i = 0; i < files.Count; i++)
                {
                    string fileName = files.Item(i).OuterXml.Contains("ows_LinkFilename") ? files.Item(i).Attributes["ows_LinkFilename"].Value : "";
                    string fileServerUrl = files.Item(i).OuterXml.Contains("ows_ServerUrl") ? files.Item(i).Attributes["ows_ServerUrl"].Value : "";
                    if (folderPath == "")
                        folderPath = documentLibraryViewName + "/";
                    if (fileName != null && fileServerUrl != null)
                    {
                        if (fileServerUrl.Contains(folderPath + fileName))
                        {
                            fileList.Add(fileName);
                        }
                    }
                }
                return fileList;
            }
        }

        /// <summary>
        /// Get file content in form of bytes 
        /// </summary>
        /// <param name="fileAbsoluteUrl"></param>
        /// <returns></returns>
        public byte[] SPGetFileContent(string fileAbsoluteUrl)
        {
            FieldInformation copyFieldInfo = new FieldInformation();
            FieldInformation[] copyFieldInfoArray = { copyFieldInfo };
            byte[] copyByteArray;
            try
            {
                CopyService.GetItem(fileAbsoluteUrl, out copyFieldInfoArray, out copyByteArray);
                return copyByteArray;
            }
            catch
            {
                // do not know how to use copyFieldInfoArray just throw it as string
                throw new Exception("SPGetFileContent failed " + copyFieldInfoArray.ToString()); 
            }
        }

        /// <summary>
        /// Upload a file
        /// </summary>
        /// <param name="folderAbsolutePath"></param>
        /// <param name="fileName"></param>
        /// <param name="fileContent"></param>
        public void SPUploadFile(string folderAbsolutePath, string fileName, Stream fileContent)
        {
            if (!folderAbsolutePath.EndsWith("/"))
                folderAbsolutePath += "/";
            string[] copyDest = { (folderAbsolutePath + fileName) };
            FieldInformation copyFieldInfo = new FieldInformation();
            FieldInformation[] copyFieldInfoArray = { copyFieldInfo };
            byte[] copyByteArray = new Byte[fileContent.Length];
            fileContent.Read(copyByteArray, 0, Convert.ToInt32(fileContent.Length));
            CopyResult copyResult1 = new CopyResult();
            CopyResult copyResult2 = new CopyResult();
            CopyResult[] copyResultArray = { copyResult1, copyResult2 };
            // Upload a file
            try
            {
                uint copyUint = CopyService.CopyIntoItems(" ", copyDest, copyFieldInfoArray, copyByteArray, out copyResultArray);
                if (copyUint == 0)
                {
                    foreach (CopyResult copyResult in copyResultArray)
                    {
                        if (copyResult.ErrorMessage != null)
                            throw new Exception("SPUploadFile failed");
                    }
                }
            }
            catch 
            {
                throw new Exception("SPUploadFile failed");
            }
        }

        /// <summary>
        /// Create a new folder
        /// </summary>
        /// <param name="folderPath"> relative path (documentlibrary/folder/subfolder/) </param>
        public void SPCreateFolder(string folderPath)
        {
            try
            {
                string strResult = DwsService.CreateFolder(folderPath);
                if (SPDwsErrorResult(strResult))
                    throw new Exception("SPCreateFolder failed");
            }
            catch 
            {
                throw new Exception("SPCreateFolder failed");
            }
        }

        /// <summary>
        /// Delete a folder 
        /// </summary>
        /// <param name="folderPath"></param>
        public void SPDeleteFolder(string folderPath)
        {
            try
            {
                string strResult = DwsService.DeleteFolder(folderPath);
                if (SPDwsErrorResult(strResult))
                    throw new Exception("SPDeleteFolder failed");
            }
            catch 
            {
                throw new Exception("SPDeleteFolder failed");
            }
        }

        /// <summary>
        /// Delete a file 
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="fileAbsolutePath"></param>
        public void SPDeleteFile(string documentLibraryName, string fileAbsolutePath)
        {
            // Get ViewID and ListID of a specific document library
            XmlNode ndListView = ListsService.GetListAndView(documentLibraryName, "");
            string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
            string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
            // Delete selected document
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement elBatch = xmlDoc.CreateElement("Batch");
            // Attention: file path
            elBatch.InnerXml = @"<Method ID='1' Cmd='Delete'>
                                  <Field Name='ID'>1</Field>
                                  <Field Name='FileRef'>" + fileAbsolutePath + "</Field>" +
                                "</Method>";
            elBatch.SetAttribute("ListVersion", "1");
            elBatch.SetAttribute("ViewName", strViewID);
            try
            {
                XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                    return;
                else
                    throw new Exception("SPDeleteFile failed");
            }
            catch 
            {
                throw new Exception("SPDeleteFile failed");
            }
        }

        public void SPRenameFolder(string documentLibraryName, string documentLibraryViewName, string folderAbsolutePath, string newFolderName)
        {
            // Process fileAbsolutePath
            if (folderAbsolutePath.EndsWith("/"))
                folderAbsolutePath = folderAbsolutePath.TrimEnd('/');
            string folderOldName = folderAbsolutePath.Substring(folderAbsolutePath.LastIndexOf('/') + 1);
            string parentFolderPath = folderAbsolutePath.Substring(0, folderAbsolutePath.LastIndexOf('/') + 1);
            if (parentFolderPath.Contains(this._sharepointUrl))
                parentFolderPath = parentFolderPath.TrimStart(this._sharepointUrl.ToCharArray());
            if (parentFolderPath.StartsWith("/"))
                parentFolderPath = parentFolderPath.TrimStart('/');
            // Get fileID value of 
            List<FolderInfo> folderInfoList = SPGetFolderInfos(documentLibraryName, documentLibraryViewName, parentFolderPath);
            var oldFolderInfo = folderInfoList.FindAll(info => info.FolderName == folderOldName).FirstOrDefault();
            if (!Object.Equals(oldFolderInfo, null))
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlNode ndListView = ListsService.GetListAndView(documentLibraryName, "");
                string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
                string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
                XmlElement elBatch = xmlDoc.CreateElement("Batch");
                elBatch.InnerXml = @"<Method ID='1' Cmd='Update'>
                                        <Field Name='ID'>" +
                                            oldFolderInfo.FolderID +
                                        "</Field>" +
                                        "<Field Name='FileRef'>" +
                                            folderAbsolutePath +
                                        "</Field>" +
                                        "<Field Name='BaseName'>" +
                                            newFolderName +
                                        "</Field>" +
                                    "</Method>";
                elBatch.SetAttribute("ListVersion", "1");
                elBatch.SetAttribute("ViewName", strViewID);
                XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                    return;
                else
                    throw new Exception("SPRenameFolder failed");
            }
        }

        /// <summary>
        /// Rename a file 
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="fileAbsolutePath">Url/documentlibraryVIEWname/folder/subfolder</param>
        /// <param name="newFileName"></param>
        public void SPRenameFile(string documentLibraryName, string documentLibraryViewName, string fileAbsolutePath, string newFileName)
        {
            // Process fileAbsolutePath
            string fileOldName = fileAbsolutePath.Substring(fileAbsolutePath.LastIndexOf('/') + 1);
            string parentFolderPath = fileAbsolutePath.Substring(0, fileAbsolutePath.LastIndexOf('/') + 1);
            if (parentFolderPath.Contains(this._sharepointUrl))
                parentFolderPath = parentFolderPath.TrimStart(this._sharepointUrl.ToCharArray());
            if (parentFolderPath.StartsWith("/"))
                parentFolderPath = parentFolderPath.TrimStart('/');
            // Get fileID value of 
            List<FileInfo> fileInfoList = SPGetFileInfos(documentLibraryName, documentLibraryViewName, parentFolderPath);
            var oldFileInfo = fileInfoList.FindAll(info => info.FileName == fileOldName).FirstOrDefault();
            if (!Object.Equals(oldFileInfo, null))
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlNode ndListView = ListsService.GetListAndView(documentLibraryName, "");
                string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;
                string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;
                if (newFileName.Contains('.'))
                    newFileName = newFileName.Substring(0, newFileName.LastIndexOf('.'));
                XmlElement elBatch = xmlDoc.CreateElement("Batch");
                elBatch.InnerXml = @"<Method ID='1' Cmd='Update'>
                                        <Field Name='ID'>" +
                                            oldFileInfo.FileID +
                                        "</Field>" +
                                        "<Field Name='FileRef'>" +
                                            fileAbsolutePath +
                                        "</Field>" +
                                        "<Field Name='BaseName'>" +
                                            newFileName +
                                        "</Field>" +
                                    "</Method>";
                elBatch.SetAttribute("ListVersion", "1");
                elBatch.SetAttribute("ViewName", strViewID);
                XmlNode ndReturn = ListsService.UpdateListItems(strListID, elBatch);
                if (ndReturn.ChildNodes[0].ChildNodes[0].InnerText.Equals("0x00000000"))
                    return;
                else
                    throw new Exception("SPRenameFile failed");
            }
        }

        /// <summary>
        /// Copy a document from one location on a server running SharePoint to another locations on the same server
        /// here all urls are absolute ones
        /// </summary>
        /// <param name="copyFromUrl"></param>
        /// <param name="copyToUrls"></param>
        public void SPCopyFileLocal(string copyFromUrl, string[] copyToUrls)
        {
            CopyResult myCopyResult1 = new CopyResult();
            CopyResult myCopyResult2 = new CopyResult();
            CopyResult[] myCopyResultArray = { myCopyResult1, myCopyResult2 };
            try
            {
                uint myUint = CopyService.CopyIntoItemsLocal(copyFromUrl, copyToUrls, out myCopyResultArray);
                if (myUint == 0)
                    return;
                else
                    throw new Exception("SPCopyFileLocal failed");
            }
            catch
            {
                string errorMessage = string.Empty;
                foreach (var myCopyResult in myCopyResultArray)
                {
                    if (myCopyResult.DestinationUrl == null)
                    {
                        errorMessage += myCopyResult.ErrorMessage;
                    }
                }
                throw new Exception("SPCopyFileLocal failed " + errorMessage);
            }
        }

        /// <summary>
        /// Copy directory 
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="documentLibrary"></param>
        /// <param name="documentLibraryView"></param>
        /// <param name="fromAbsolutePath">URL/documentlibraryVIEW/folder/subfolder</param>
        /// <param name="toAbsolutePath">URL/documentlibraryVIEW/folder/subfolder</param>
        public void SPCopyFolderLocal(string documentLibraryName, string documentLibraryViewName, string folderName, string fromAbsoluteParentPath, string toAbsoluteParentPath)
        {
            if(!fromAbsoluteParentPath.EndsWith("/"))
                fromAbsoluteParentPath += "/";
            if(!toAbsoluteParentPath.EndsWith("/"))
                    toAbsoluteParentPath += "/";
            string processedFromAbsoluteParentPath = fromAbsoluteParentPath;
            if (processedFromAbsoluteParentPath.Contains(this._sharepointUrl))
                processedFromAbsoluteParentPath = processedFromAbsoluteParentPath.TrimStart(this._sharepointUrl.ToCharArray());
            string processedToAbsoluteParentPath = toAbsoluteParentPath;
            if (processedToAbsoluteParentPath.Contains(this._sharepointUrl))
                processedToAbsoluteParentPath = processedToAbsoluteParentPath.TrimStart(this._sharepointUrl.ToCharArray());
            // Create a new folder to destination path
            SPCreateFolder(processedToAbsoluteParentPath.TrimStart('/') + folderName);
            // Get files of a specific folder
            List<string> fileList = SPGetFiles(documentLibraryName, documentLibraryViewName, processedFromAbsoluteParentPath + folderName);
            // Copy returned files locally
            if (fileList.Count > 0)
            {
                foreach (var file in fileList)
                {
                     string[] destUrls = { toAbsoluteParentPath + folderName + "/" + file};
                    SPCopyFileLocal((fromAbsoluteParentPath + folderName + "/" + file), destUrls);
                }
            }
            // Get subfolders of a specific folder and recursively call SPCopyFolderLocal
            List<string> folderList = SPGetFolders(documentLibraryName, documentLibraryViewName, processedFromAbsoluteParentPath + folderName);
            if (folderList.Count > 0)
            {
                foreach (var folder in folderList)
                {
                    SPCopyFolderLocal(documentLibraryName, documentLibraryViewName, folder, (fromAbsoluteParentPath + folderName), (toAbsoluteParentPath + folderName));
                }
            }
        }

        /// <summary>
        /// Move one folder from old place to new place
        /// </summary>
        /// <param name="documentLibraryName"></param>
        /// <param name="documentLibraryViewName"></param>
        /// <param name="folderName"></param>
        /// <param name="fromAbsoluteParentPath"></param>
        /// <param name="toAbsoluteParentPath"></param>
        public void SPMoveFolderLocal(string documentLibraryName, string documentLibraryViewName, string folderName, string fromAbsoluteParentPath, string toAbsoluteParentPath)
        {
            if (!fromAbsoluteParentPath.EndsWith("/"))
                fromAbsoluteParentPath += "/";
            if (!toAbsoluteParentPath.EndsWith("/"))
                toAbsoluteParentPath += "/";
            string processedFromAbsoluteParentPath = fromAbsoluteParentPath;
            if (processedFromAbsoluteParentPath.Contains(this._sharepointUrl))
                processedFromAbsoluteParentPath = processedFromAbsoluteParentPath.TrimStart(this._sharepointUrl.ToCharArray());
            string processedToAbsoluteParentPath = toAbsoluteParentPath;
            if (processedToAbsoluteParentPath.Contains(this._sharepointUrl))
                processedToAbsoluteParentPath = processedToAbsoluteParentPath.TrimStart(this._sharepointUrl.ToCharArray());
            // Create a new folder to destination path
            SPCreateFolder(processedToAbsoluteParentPath.TrimStart('/') + folderName);
            // Get files of a specific folder
            List<string> fileList = SPGetFiles(documentLibraryName, documentLibraryViewName, processedFromAbsoluteParentPath + folderName);
            // Copy returned files locally
            if (fileList.Count > 0)
            {
                foreach (var file in fileList)
                {
                    string[] destUrls = { toAbsoluteParentPath + folderName + "/" + file };
                    SPCopyFileLocal((fromAbsoluteParentPath + folderName + "/" + file), destUrls);
                }
            }
            // Get subfolders of a specific folder and recursively call SPCopyFolderLocal
            List<string> folderList = SPGetFolders(documentLibraryName, documentLibraryViewName, processedFromAbsoluteParentPath + folderName);
            if (folderList.Count > 0)
            {
                foreach (var folder in folderList)
                {
                    SPCopyFolderLocal(documentLibraryName, documentLibraryViewName, folder, (fromAbsoluteParentPath + folderName), (toAbsoluteParentPath + folderName));
                }
            }
            // Delete folder from old path
            SPDeleteFolder(processedFromAbsoluteParentPath.TrimStart('/') + folderName);
        }

        /// <summary>
        /// Process whether Dws web services works well or not
        /// </summary>
        /// <param name="ResultFragment"></param>
        /// <returns></returns>
        private bool SPDwsErrorResult(string ResultFragment)
        {
            StringReader srResult = new StringReader(ResultFragment);
            XmlTextReader xtr = new XmlTextReader(srResult);
            xtr.Read();
            if (xtr.Name.Equals("Error"))
                return true;
            return false;
        }
    }
}